<?php

class Util_Pager {

    // 地址的前缀
    private $_prefixUrl   = '';

    // 地址的后缀
    private $_suffixUrl   = '';

    // 所有数据
    private $_itemData    = null;

    // 总的数据条数
    private $_totalItems  = 0;

    // 文件名
    private $_fileName    = '';

    // 每页显示数据的条数
    private $_perPage     = 10;

    // 当前页两边的显示的页数
    private $_delta       = 2;

    // 当面页号
    private $_currentPage = 1;

    // 链接属性
    private $_linkAttribute = "target='_top'";

    // 连接的样式
    private $_linkClass   = '';

    // 页号变量名
    private $_urlVar      = 'page';

    private $_altPrev     = '&laquo;';

    private $_altNext     = '&raquo;';

    private $_altPrevClass     = '';

    private $_altNextClass     = '';

    private $_pagePrev = '';

    private $_pageNext = '';

    private $_dotClass     = '';

    // 上一分页<<
    private $_firstImg     = '1';

    // 下一分页>>
    private $_lastImg     = '';

    // 更多文字显示
    private $_pageName = 'more';

    private $_expanded    = true;

    private $_curPageClass= '';

    // 需要忽略的字段
    private $_ignoreQuery = array();

    // 如果没有分页是是否显示分页
    private $_clearIfVoid = true;

    // 把所有的参数赋给这个变量
    private $_assignQuery = '';

    // 是否显示总页数
    private $_showTotalItems = false;

    // 每个URL中添加总记录数
    private $_urlAddTotalItems = false;

    // 显示更多链接
    private $_showMorePage = false;

    // 显示上一页、下一页链接
    private $_showPreAndNextPage= false;

    // 是否显示第一页和最后一页，如果不显示也将显示省略号
    private $_showFirstAndLastPage= true;

    // 显示跳转输入框
    private $_showJumpPage = false;

    // 链接后的锚点字符串
    private $_fragment = '';

    public $range = array();

    public function __construct($options = array()) {

        $this->_setOptions($options);
        $this->_generatePageData();

        if ($this->_urlAddTotalItems) {
            $this->_ignoreQuery[] = 'totalItems';
        }

        //打印上一页
        if ($this->_showPreAndNextPage) {
            if ($this->_totalPages > 1) {
                $this->links .= $this->_getBackLink();
            }
        } else {
            if ($this->_currentPage > 2 * $this->_delta + 2) {
                $this->links .= $this->_getBackLink();
            }
        }

        //打印第一页
        if ($this->_showFirstAndLastPage && $this->_currentPage > 2 * $this->_delta && $this->_totalPages > 2 * $this->_delta + 1 ) {
            $this->links .= $this->_printFirstPage();
        }



        /********************************************************/
        //增加判断前后是否需要省略号的逻辑 防止出现 1...2 和 5...6 这两种情况   add by averyhuang
        $before = $this->_currentPage - 2;
        $after = $this->_totalPages - $this->_currentPage - 1;
        $beforeForExpand = 0;

        if($before < 0) $before = 0;
        if($before > $this->_delta){
            $before = $this->_delta;
            $beforeForExpand = $this->_currentPage - $before - 2;
        }
        if($after < 0) $after = 0;
        if($after > $this->_delta && !$this->_expanded) $after = $this->_delta;
        if($after < $this->_delta && $this->_expanded){
            for($i=$this->_delta - $after; $beforeForExpand > 0 && $i>0; $beforeForExpand--, $i--)
                $before++;
        }
        if($this->_expanded) $after = min($after , 2*$this->_delta-$before);

        $isNeedBefore = false;
        $isNeedAfter = false;
        if($this->_currentPage - $before > 2) $isNeedBefore = true;
        if($this->_currentPage + $after < $this->_totalPages - 1) $isNeedAfter = true;
        /********************************************************/



        //打印省略
        if ($this->_showFirstAndLastPage && $this->_totalPages > 2 * $this->_delta + 1 && $this->_currentPage > 2 * $this->_delta && $isNeedBefore) {
            $this->links .= $this->getPageUrl(null);
        }

        $this->links .= $this->_getPageLinks();

        // 最后一页和省略
        if ($this->_showFirstAndLastPage && $this->_totalPages > (2 * $this->_delta + 1)) {
            if ($this->_currentPage + $this->_delta + 1 < $this->_totalPages && $isNeedAfter) {
                $this->links .= $this->getPageUrl(null);
            }
            $this->links .= $this->_printLastPage();
        }

        if ($this->_showJumpPage && $this->_totalPages > 1) {
            $this->links .= $this->_getJumpPage();
        }
        // 下一页链接
        if ($this->_showPreAndNextPage) {
            if ($this->_totalPages > 1 && $this->getCurrentPageId() < $this->_totalPages) {
                $this->links .= $this->_getNextLink();
            }
        } else {
            if ($this->_currentPage + $this->_delta + 1 < $this->_totalPages) {
                $this->links .= $this->_getNextLink();
            }
        }

        if ($this->_showMorePage && $this->_totalPages > 1) {
            $this->links .= $this->_getMoreLink();
        }

        if ($this->_showTotalItems == true && $this->_totalItems) {
            $this->links .= $this->_getTotalItems();
        }

    }

    public static function makeLinks($options) {

        $pager = new self($options);
        return $pager->getLinks();
    }

    public function getBackLinkByHtml($html) {

        $link = $this->getPageUrl($this->getPreviousPageId(), '', true);
        return sprintf($html, $link);
    }

    public function getNextLinkByHtml($html) {

        $link = $this->getPageUrl($this->getNextPageId(), '', true);
        return sprintf($html, $link);
    }

    public function getLinks() {

        return $this->links;
    }

    public function getPageData($pageId = null) {

        if ($pageId !== null) {
            if (!empty($this->_pageData[$pageId])) {
                return $this->_pageData[$pageId];
            }
        } else {
            return false;
        }

        if (!isset($this->_pageData)) {
            $this->_generatePageData();
        }

        return $this->getPageData($this->_currentPage);
    }

    public function numPages() {

        return (int)$this->_totalPages;
    }

    public function getOffsetByPageId($pageId = null) {

        $pageId = ($pageId) ? $pageId : $this->_currentPage;

        if (isset($this->_pageData)) {
            $this->_generatePageData();
        }
        if ($this->_totalPages > 1) {
            return array(
                         max($pageId - $this->_delta , 1),
                         min($pageId + $this->_delta , $this->numPages())
                        );
        } else {
            return array(0, 0);
        }
    }

    public function getCurrentPageId() {

        return $this->_currentPage;
    }

    public function getNextPageId() {

        return ($this->getCurrentPageId() == $this->numPages()) ?
            false : $this->getCurrentPageId() + 1;
    }

    public function getPreviousPageId() {

        return $this->isFirstPage() ? false : $this->getCurrentPageId() - 1;
    }

    public function getTotalItems() {

        return $this->_totalItems;
    }

    public function getTotalPages() {

        return (int)$this->_totalPages;
    }

    public function isFirstPage() {
        return ($this->_currentPage == 1);
    }

    public function isLastPage() {
        return ($this->_currentPage == $this->_totalPages);
    }

    private function _getBackLink() {

        if ($this->_currentPage > 1) {
            $back = $this->getPageUrl($this->getPreviousPageId(), $this->_altPrev);
        } else {
            $back = '';
        }
        return $back;
    }

    private function _getNextLink() {

        if ($this->_currentPage < $this->_totalPages) {
            $next = $this->getPageUrl($this->getNextPageId(), $this->_altNext);
        } else {
            $next = '';
        }
        return $next;
    }

    private function _getMoreLink() {

        $pageLink = $this->_prefixUrl . $this->_suffixUrl ;
        // 更多.
        $pageId = $this->_totalPages + 1;
        if ($this->_assignQuery) {
            $specialUrl = $this->_assignQuery . '=' . urlencode($this->_getPageLink()) . $pageId;
        } else {
            $specialUrl = $this->_getPageLink() . $pageId;
        }
        if ($pageLink) {
            $delim  = strpos($pageLink, '?') ? '&' : '?';
        } else {
            $delim  = '';
        }
        $pageLink .= $delim . $specialUrl;

        if ($this->_fragment) {
            $pageLink .= '#' . $this->_fragment;
        }

        $pageName = $this->_pageName;
        $pageUrl = sprintf('<a %s href="%s" %s>%s</a>', $this->_linkClassString, $pageLink, $this->_linkAttribute, $pageName);

        return $pageUrl;
    }

    private function _getPageLinks() {

        $links = '';
        if ($this->_totalPages > ( 2 * $this->_delta + 1)) {
            if ($this->_expanded) {
                if ($this->_totalPages - $this->_delta <= $this->_currentPage) {
                    $_expansion_before = $this->_currentPage - ($this->_totalPages - $this->_delta);
                    if ($this->_currentPage != $this->_totalPages)  $_expansion_before++;
                } else {
                    $_expansion_before = 0;
                }
                // 从第一页到距当前页_delta页
                for($i = $this->_currentPage - $this->_delta - $_expansion_before; $_expansion_before; $_expansion_before--, $i++) {
                    // 打算分隔符，暂时不用先留着
                    if (($i != $this->_currentPage + $this->_delta) && ($i != $this->_totalPages - 1)) {
                        $_print_separator_flag = true;
                    } else {
                        $_print_separator_flag = false;
                    }


                    //防止出现重复两个一页    add by averyhuang
                    if($i != 1 || !$this->_showFirstAndLastPage){
                        $this->range[$i] = false;
                        $links .= $this->getPageUrl($i);
                    }


                }
            }
            $_expansion_after = 0;

            // 距当前页_delta左右两边的页
            for($i = $this->_currentPage - $this->_delta;
                ($i <= $this->_currentPage + $this->_delta) && ($i < $this->_totalPages);
                $i++) {

                if ($i < 1 && $i != $this->_currentPage) {
                    $_expansion_after ++;
                    continue;
                }

                // 打算分隔符，暂时不用先留着
                if (($i != $this->_currentPagte + $this->_delta) && ($i != $this->_totalPages - 1)) {
                    $_print_separator_flag = true;
                } else {
                    $_print_separator_flag = false;
                }

                if ($i == $this->_currentPage) {
                    $this->range[$i] = true;
                    $links .= $this->getPageUrl($i);
                } else {
                    $this->range[$i] = false;
                    $links .= $this->getPageUrl($i);
                }
            }

            // 当前页是最后一页
            if ($this->_currentPage == $this->_totalPages) {
                $this->range[$this->_currentPage] = true;
                $links .= $this->getPageUrl($this->_totalPages);
            }

            // 从距当前_delta页到最后
            if ($this->_expanded && $_expansion_after) {
                for($i = $this->_currentPage + $this->_delta + 1 ; $_expansion_after; $_expansion_after--, $i++) {
                    if(($_expansion_after != 1)) {
                        $_print_separator_flag = true;
                    } else {
                        $_print_separator_flag = false;
                    }

                    $this->range[$i] = false;
                    $links .= $this->getPageUrl($i);
                }
            }
        } else {
            for ($i = 1; $i <= $this->_totalPages; $i++) {
                if ($i != $this->_currentPage) {
                    $this->range[$i] = false;
                    $links .= $this->getPageUrl($i);
                } else {
                    $this->range[$i] = true;
                    $links .= $this->getPageUrl($i);
                }
            }
        }
        if ($this->_clearIfVoid) {
            if ($this->numPages() < 2) $links = '';
        }
        return $links;
    }

    private function _printFirstPage() {

        if ($this->isFirstPage()) {
            return '';
        } else {
            return $this->getPageUrl(1, $this->_firstImg);
        }
    }

    private function _printLastPage() {

        if ($this->isLastPage()) {
            return '';
        } else {
            return $this->getPageUrl($this->numPages(), $this->numPages());
        }
    }

    private function _generatePageData() {

        if ($this->_itemData !== null) {
            $this->_totalItems = count($this->_itemData);
        }
        $this->_totalPages = ceil((float)$this->_totalItems / (float) $this->_perPage);

        // 如果显示更多时，有可能出现不存在的页码
        if ($this->_urlAddTotalItems && $this->_currentPage > $this->_totalPages) {
            $this->_totalPages += 1;
        } else {
            $this->_currentPage= ($this->_currentPage > $this->_totalPages) ? $this->_totalPages : $this->_currentPage;
        }

        $i = 0;
        if (!empty($this->_itemData)) {
            foreach ($this->_itemData as $key => $value) {
                $this->_pageData[$i][$key] = $value;
                if (count($this->_pageData[$i]) >= $this->_perPage){
                    $i++;
                }
            }
        } else {
            $this->_pageData = array();
        }
    }

    public function getPageUrl($pageId, $pageName = null, $isReturnLink = false) {

        $pageLink = $this->_prefixUrl . $this->_suffixUrl ;
        if ($this->_assignQuery) {
            $specialUrl = $this->_assignQuery . '=' . urlencode($this->_getPageLink()) . $pageId;
        } else {
            $specialUrl = $this->_getPageLink() . $pageId;
        }
        if ($pageLink) {
            $delim  = strpos($pageLink, '?') ? '&' : '?';
        } else {
            $delim  = '';
        }
        $pageLink .= $delim . $specialUrl;

        // 分页URL中添加总记录数显示
        if ($this->_urlAddTotalItems) {
            $pageLink .= '&totalItems=' . $this->_totalItems;
        }

        if ($this->_fragment) {
            $pageLink .= '#' . $this->_fragment;
        }

        if ($isReturnLink) {
            return $pageLink;
        }

        if ($pageId === null) {
            $pageUrl = sprintf('<strong %s>...</strong>', $this->_dotClassString);
            return $pageUrl;
        }
        if ($pageName === null) {
            if ($this->_currentPage == $pageId) {
                $pageUrl = sprintf('<strong %s>%d</strong>', $this->_curPageClassString, $pageId);
            } else {
                $pageUrl = sprintf('<a %s href="%s" %s >%s%d%s</a>', $this->_linkClassString, $pageLink, $this->_linkAttribute, $this->_pagePrev, $pageId, $this->_pageNext);
            }
        } else {
            if ($this->_currentPage == $pageId) {
                $pageUrl = sprintf('<strong %s>%d</strong>', $this->_curPageClassString, $pageId);
            } else {
                if ($pageName == $this->_altPrev) {
                    $pageUrl = sprintf('<a class="%s" href="%s" %s>%s</a>',
                                       $this->_altPrevClass, $pageLink, $this->_linkAttribute, $pageName);
                } else if ($pageName == $this->_altNext) {
                    $pageUrl = sprintf('<a class="%s" href="%s" %s>%s</a>',
                                       $this->_altNextClass, $pageLink, $this->_linkAttribute, $pageName);
                } else {
                    $pageUrl = sprintf('<a %s href="%s" %s>%s</a>',
                                       $this->_linkClassString, $pageLink, $this->_linkAttribute, $pageName);
                }
            }

        }
        return $pageUrl;
    }

    /**
     * 显示跳转输入框
     * @return string
     */
    private function _getJumpPage() {
        $pageLink = $this->_prefixUrl . $this->_suffixUrl ;
        if ($this->_assignQuery) {
            $specialUrl = $this->_assignQuery . '=' . urlencode($this->_getPageLink());
        } else {
            $specialUrl = $this->_getPageLink();
        }
        if ($pageLink) {
            $delim  = strpos($pageLink, '?') ? '&' : '?';
        } else {
            $delim  = '';
        }
        $pageLink .= $delim . $specialUrl;

        $pageUrl = sprintf('<label for="jumpPage" class="pageI"><input name="jumpPage" id="jumpPage" type="text" style="width:20px;" %s %s onkeyup="if(event.keyCode==13) {window.location=\'%s\'+this.value;}" >/%s页</label>',
                $this->_linkClassString, $this->_linkAttribute, $pageLink, $this->_totalPages);
        return $pageUrl;
    }

    /**
     * 到当前页面的链接，可能并不是真正到达这个页面的链接地址
     */
    protected function _getPageLink() {

        $linkQuery   = array();
        $linkQueryString = '';
        $this->_ignoreQuery[] = $this->_urlVar;
        if ($this->_query) {
            $getParams = $this->_query;
        } else {
            $getParams = $_GET;
        }
        if ($getParams) {
            $ignoreKey = array_flip($this->_ignoreQuery);
            $linkQuery = array_diff_key($getParams, $ignoreKey);
            if ($linkQuery && is_array($linkQuery)) {
                $linkQueryString = $this->_fileName . '?' . http_build_query($linkQuery);
            } else {
                $linkQueryString = $this->_fileName ;
            }
        }
        $delim = (strpos($linkQueryString, '?') !== false) ? '&' : '?';
        $linkQueryString .= $delim . $this->_urlVar . '=';

        return $linkQueryString;
    }

    protected function _getTotalItems() {

        $pageUrl = sprintf('&nbsp;&nbsp;&nbsp;&nbsp;共%d条记录', $this->_totalItems);
        return $pageUrl;
    }

    private function _setOptions($options) {

        $allowed_options = array(
                                 'prefixUrl',
                                 'suffixUrl',
                                 'itemData',
                                 'totalItems',
                                 'fileName',
                                 'perPage',
                                 'delta',
                                 'currentPage',
                                 'linkClass',
                                 'fragment',
                                 'urlVar',
                                 'altPrev',
                                 'altNext',
                                 'altPrevClass',
                                 'altNextClass',
                                 'dotClass',
                                 'prevImg',
                                 'nextImg',
                                 'pagePrev',
                                 'pageNext',
                                 'pageName',
                                 'expanded',
                                 'curPageClass',
                                 'ignoreQuery',
                                 'linkAttribute',
                                 'assignQuery',
                                 'showTotalItems',
                                 'urlAddTotalItems',
                                 'showMorePage',
                                 'showPreAndNextPage',
                                 'showFirstAndLastPage',
                                 'showJumpPage',
                                 'query',
                                     );
        foreach ($options as $key => $value) {
            if (in_array($key, $allowed_options) && ($value !== null)) {
                $this->{'_' . $key} = $value;
            }
        }
        $this->_prefixUrl = rtrim($this->_prefixUrl, '/');
        $this->_suffixUrl = rtrim($this->_suffixUrl, '/');

        if (strlen($this->_linkClass)) {
            $this->_linkClassString = 'class="' . $this->_linkClass . '"';
        } else {
            $this->_linkClassString = '';
        }

        if (strlen($this->_curPageClass)) {
            $this->_curPageClassString = 'class="' . $this->_curPageClass . '"';
        } else {
            $this->_curPageClassString = '';
        }

        if (strlen($this->_dotClass)) {
            $this->_dotClassString = 'class="' . $this->_dotClass . '"';
        } else {
            $this->_dotClassString = '';
        }

        if ($this->_perPage < 1) {
            $this->_perPage = 1;
        }

        if (!$this->_currentPage) {
            $this->_currentPage = intval(Yaf_Application::app()->getDispatcher()->getRequest()->get($this->_urlVar));
        }
        $this->_currentPage = max($this->_currentPage, 1);
    }

    /**
     * resolveOptions
     * 解决Page参数关系
     *
     * @param  integer $pageOption 页面数据参数
     *  + perPage 每页显示数
     *  + currentPage 当前页数
     *  + start 开始记录数
     * @return array
     */
    public static function resolveOptions(&$options) {

        if (!$options) {
            return array();
        }

        if (!$options['perPage']) {
            $options['perPage'] = 20;
        }

        if (!$options['currentPage']) {
            $options['currentPage'] = Yaf_Application::app()->getDispatcher()->getRequest()->get('page', 1);
        }

        if ($options['totalItems'] === null) {
            unset($options['totalItems']);
        }

        if ($options['totalItems'] > 0) {
            unset($options['overRange']);
            $pageNum = ceil($options['totalItems'] / $options['perPage']);
            if ($options['currentPage'] > $pageNum) {
                $options['currentPage'] = $pageNum;
            }
        } elseif ($options['currentPage'] > 1) {
            $options['overRange'] = true;
        }

        // 显示分页处理 中MORE 设置
        // $interval = 1000;
        // if ($options['totalItems']) {
            // $n = intval(($options['totalItems'] - 1) / $interval);
            // if ($n * $interval + 1 == $options['totalItems']) {
                // $options['showMorePage'] = true;
            // } else {
                // $options['showMorePage'] = false;
            // }
        // }

        $start = 0;
        if ($options['currentPage']) {
            $start = intval(($options['currentPage'] - 1) * $options['perPage']);
        }
        if ($options['start'] <= $start) {
            $options['start'] = $start;
        }

        $options['to']    = intval($options['start'] + $options['perPage'] - 1);

        return $options;
    }

}
